/**
 * Highscore.java
 */
package rainingcatsdogs;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;

import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreFullException;
import javax.microedition.rms.RecordStoreNotFoundException;

/**
 * Contains the functions related to storing high scores in a record store.
 * 
 * @author jl00163
 */
public class Highscore {

	/** Name of the recordStore. */
	private static final String REC_NAME = "HighScore";

	/** The lowest score in the record store. */
	private int lowestScore;

	/** Allows persistent storage of the high scores. */
	private RecordStore scoreStore;

	/** The vector representation of the high scores. */
	private Vector scoreVector;

	/**
	 * Constructor for the HighScore class.
	 */
	public Highscore() {
		try {
			this.scoreStore = RecordStore.openRecordStore(REC_NAME, true);

			// If the record store is new, ten records will be added.
			if (this.scoreStore.getNumRecords() == 0) {
				this.addInitialRecords();
			}

			this.scoreStore.enumerateRecords(null, null, true);

			this.scoreStore.closeRecordStore();
		} catch (RecordStoreFullException e) {
			e.printStackTrace();
		} catch (RecordStoreNotFoundException e) {
			e.printStackTrace();
		} catch (RecordStoreException e) {
			e.printStackTrace();
		}

		this.scoreVector = this.generateVector();
	}

	/**
	 * Adds a set of 10 fake records to fill the record store.
	 * 
	 * @return True if the records have been added, false if the record is not
	 *         added.
	 */
	private boolean addInitialRecords() {
		boolean added = false;

		try {
			this.scoreStore = RecordStore.openRecordStore(REC_NAME, false);

			// Arrays holding the names and scores.
			String[] names = { "ORY", "JRL", "AWG", "KAR", "ADG", "RAF", "DAB",
					"BOO", "CIA", "BBM" };
			int[] scores = { 1000000, 519000, 492000, 488000, 360000, 250000,
					200000, 150000, 100000, 5000 };

			ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
			DataOutputStream dataTypeStream = new DataOutputStream(byteStream);
			byte[] record;

			for (int i = 0; i < names.length; i++) {
				dataTypeStream.writeUTF(names[i]);
				dataTypeStream.writeInt(scores[i]);

				dataTypeStream.flush();

				record = byteStream.toByteArray();
				scoreStore.addRecord(record, 0, record.length);

				byteStream.reset();
			}
			byteStream.close();
			dataTypeStream.close();

			this.scoreStore.closeRecordStore();
		} catch (RecordStoreFullException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RecordStoreNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RecordStoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return added;
	}

	/**
	 * Generates a vector representation of the high score board in descending
	 * order of the scores.
	 * 
	 * @return Vector holding the high scores.
	 */
	public Vector generateVector() {
		Vector highScore = new Vector(10, 0);

		try {
			this.scoreStore = RecordStore.openRecordStore(REC_NAME, false);

			byte[] recordByte = new byte[50];
			ByteArrayInputStream byteStream = new ByteArrayInputStream(
					recordByte);
			DataInputStream dataTypeStream = new DataInputStream(byteStream);

			String[] record;
			for (int i = 1; i <= this.scoreStore.getNumRecords(); i++) {

				this.scoreStore.getRecord(i, recordByte, 0);
				record = new String[2];
				record[0] = dataTypeStream.readUTF();
				record[1] = String.valueOf(dataTypeStream.readInt());
				highScore.addElement(record);

				// Reset so read starts at beginning of array
				byteStream.reset();
			}

			this.scoreStore.closeRecordStore();

			String[] lowestRecord = (String[]) highScore.lastElement();
			this.lowestScore = Integer.parseInt(lowestRecord[1]);
		} catch (RecordStoreFullException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RecordStoreNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RecordStoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return highScore;
	}

	/**
	 * Gets the lowest score on the leader board.
	 * 
	 * @return The lowest score on the leader board.
	 */
	public int getLowestScore() {
		return this.lowestScore;
	}

	/**
	 * Places a record containing a name and a score into the record store. The
	 * record is added in the correct position so all the records in the record
	 * store are in descending order of the scores.
	 * 
	 * @param name
	 *            The name to be inserted in the record store.
	 * @param score
	 *            The score to be inserted into the record store.
	 * @return Whether the record specified in the parameters are added.
	 */
	public boolean replaceRecord(String name, int score) {
		boolean replaced = false;

		try {
			this.scoreStore = RecordStore.openRecordStore(REC_NAME, false);

			String[] pointer;
			int counter = 0;

			// Finds the position where the new record should be added in.
			do {
				pointer = (String[]) this.scoreVector.elementAt(counter);
				counter = counter + 1;
			} while (Integer.parseInt(pointer[1]) > score);

			ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
			DataOutputStream dataTypeStream = new DataOutputStream(byteStream);
			byte[] record;
			byte[] temp;

			dataTypeStream.writeUTF(name);
			dataTypeStream.writeInt(score);
			dataTypeStream.flush();
			record = byteStream.toByteArray();
			byteStream.reset();
			byteStream.close();
			dataTypeStream.close();

			// Inserts the new record into the position and moves all the
			// records at that position and below one step down. Since the last
			// record isn't added back into the record store, the last record
			// should be cleared up by the garbage collection.
			for (int i = counter; i <= this.scoreStore.getNumRecords(); i++) {
				temp = this.scoreStore.getRecord(i);
				this.scoreStore.setRecord(i, record, 0, record.length);
				record = temp;
			}

			this.scoreStore.closeRecordStore();
			this.scoreVector = this.generateVector();
			replaced = true;
		} catch (RecordStoreFullException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RecordStoreNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RecordStoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return replaced;
	}

	/**
	 * Creates a string representation of the high scores.
	 * 
	 * @override
	 * @return String representation of the high scores.
	 */
	public String toString() {
		String scores = "";
		String[] record = new String[2];
		for (int i = 0; i < this.scoreVector.size() - 1; i++) {
			record = (String[]) this.scoreVector.elementAt(i);
			scores += "  " + (i + 1) + "  " + record[0] + "   " + record[1]
					+ "\n";
		}
		record = (String[]) this.scoreVector.lastElement();
		scores += " " + (10) + " " + record[0] + "   " + record[1] + "\n";
		return scores;
	}
}